/*
yield表达式本身没有返回值，或者说总是返回undefined。
重点：next方法可以带一个参数，该参数就会被当作上一个yield表达式的返回值。

定义了一个可以无限运行的 Generator 函数f，
当next方法带一个参数true时，
变量reset就被重置为这个参数（即true），
因此i会等于-1，下一轮循环就会从-1开始递增。
*/

function* f() {
	for (var i = 0; true; i++) { //无限循环
		var reset = yield i; //如果next方法没有参数，每次运行到yield表达式，变量reset的值总是undefined。注意：yield一般都是没返回值的
		if (reset) {
			i = -1;
		}
	}
}
var g = f();
g.next() // { value: 0, done: false }
g.next() // { value: 1, done: false }
g.next(true) // { value: 0, done: false }




/*
这个功能有很重要的语法意义。Generator 函数从暂停状态到恢复运行，它的上下文状态（context）是不变的。
通过next方法的参数，就有办法在 Generator 函数开始运行之后，继续向函数体内部注入值。
也就是说，可以在 Generator 函数运行的不同阶段，从外部向内部注入不同的值，从而调整函数行为。
*/



/*
第二次运行next方法的时候不带参数，导致 y 的值等于2 * undefined（即NaN），
除以 3 以后还是NaN，因此返回对象的value属性也等于NaN。
第三次运行Next方法的时候不带参数，所以z等于undefined，返回对象的value属性等于5 + NaN + undefined，即NaN。

对应知识点 => next方法可以带一个参数，该参数就会被当作上一个yield表达式的返回值。

如果向next方法提供参数，返回结果就完全不一样了。
第一次调用b的next方法时，返回x+1的值6；
第二次调用next方法，将上一次yield表达式的值设为12，因此y等于24，返回y / 3的值8；
第三次调用next方法，将上一次yield表达式的值设为13，因此z等于13，这时x等于5，y等于24，所以return语句的值等于42


!!!注意，由于next方法的参数表示上一个yield表达式的返回值，所以在第一次使用next方法时，传递参数是无效的。
V8 引擎直接忽略第一次使用next方法时的参数，只有从第二次使用next方法开始，参数才是有效的。
从语义上讲，第一个next方法用来启动遍历器对象，所以不用带有参数。!!!
*/
function* foo(x) {
	var y = 2 * (yield(x + 1));
	var z = yield(y / 3);
	return (x + y + z);
}

var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}

var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false } z=8 y=24
b.next(13) // { value:42, done:true } z=13 x=5 y=24 




/*
再看一个通过next方法的参数，向 Generator 函数内部输入值的例子。
每次通过next方法向 Generator 函数输入值，然后打印出来。
*/
function* dataConsumer() {
	console.log('Started');
	console.log(`1. ${yield}`); //yield之前的代码 需要在当次next对应的距离最近的yield释放后执行
	console.log(`2. ${yield}`);
	return 'result';
}
let genObj = dataConsumer();
genObj.next();
// Started
genObj.next('a')
// 1. a
genObj.next('b')
// 2. b



/*
如果一定想要第一次调用next方法时，就能够输入值，可以在 Generator 函数外面再包一层。
Generator 函数如果不用wrapper先包一层，是无法第一次调用next方法，就输入参数的。

说白了就是提前用一次next 还是比较难理解的哈
*/
function wrapper(generatorFunction) {
	return function(...args) {
		let generatorObject = generatorFunction(...args);
		generatorObject.next();
		return generatorObject;
	};
}

const wrapped = wrapper(function*() {
	console.log(`First input: ${yield}`);
	return 'DONE';
});

wrapped().next('hello!')
// First input: hello!
